package cn.virens.database.common;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.page.PageMethod;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.virens.components.page.PageParamUser;
import cn.virens.components.page.PageResult;
import cn.virens.database.common.mapper.BaseMapper;
import cn.virens.database.common.mapper.ExampleWrapper;
import cn.virens.exception.APIException;
import tk.mybatis.mapper.entity.Example;

/**
 * 通用service实现类
 * 
 * @author     virens
 * @param  <M> DO层接口类型
 * @param  <T> 实体类型
 */
public abstract class BaseViewServiceImpl<M extends BaseMapper<T>, T extends BaseModel> implements BaseViewService<T> {
	protected final Logger logger = LoggerFactory.getLogger(getClass());

	protected final Class<T> clazz;

	@Autowired
	protected M mBaseMapper;

	public BaseViewServiceImpl(Class<T> clazz) {
		this.clazz = clazz;
	}

	@Override
	@Transactional(readOnly = true)
	public List<? extends T> selectAll(Map<String, Object> param) {
		return mBaseMapper.selectByExample(ExampleWrapper.of(clazz, param));
	}

	@Override
	@Transactional(readOnly = true)
	public T selectOne(Map<String, Object> param) {
		if (param != null && param.isEmpty() == false) {
			return selectOne(ExampleWrapper.of(clazz, param));
		} else {
			throw new APIException("Null", "param is null!");
		}
	}

	@Override
	@Transactional(readOnly = true)
	public T selectOne(Serializable id) {
		return mBaseMapper.selectByPrimaryKey(id);
	}

	@Override
	@Transactional(readOnly = true)
	public PageResult<?> selectPage(PageParamUser pageParam) {
		return doPageSelect(pageParam, () -> doPageQuery(pageParam));
	}

	/**
	 * 查询一条记录
	 * 
	 * @param  example 查询条件
	 * @return         记录
	 */
	protected T selectOne(Example example) {
		return mBaseMapper.selectOne(example);
	}

	/**
	 * 默认查询全部，如需使用分页，并且有条件查询，复写该方法
	 * 
	 * @param  param 查询参数
	 * @return       记录列表
	 */
	protected List<?> doPageQuery(PageParamUser param) {
		return selectAll(param.getParams());
	}

	/**
	 * 执行分页查询
	 * 
	 * @param  <R>    返回类型
	 * @param  param  查询参数
	 * @param  action 查询动作
	 * @return        PageResult
	 */
	protected <R> PageResult<R> doPageSelect(PageParamUser param, Supplier<List<R>> action) {
		PageResult<R> answer = new PageResult<>();
		try {
			// 获取分页参数
			Integer pageSize = ObjectUtil.defaultIfNull(param.getPageSize(), 20);
			Integer pageNum = ObjectUtil.defaultIfNull(param.getPageNum(), 1);

			// 设置分页信息
			Page<Object> _page = PageMethod.startPage(pageNum, pageSize);
			_page.setOrderBy(ObjectUtil.defaultIfNull(param.getOrderBy(), null));
			_page.setCount(ObjectUtil.defaultIfNull(param.isCount(), true));

			// 执行查询 并 获取查询结果中的分页信息
			PageInfo<R> pageInfo = PageInfo.of(action.get());
			answer.setPageSize(pageInfo.getPageSize());
			answer.setPageNum(pageInfo.getPageNum());
			answer.setPages(pageInfo.getPages());
			answer.setTotal(pageInfo.getTotal());
			answer.setSize(pageInfo.getSize());
			answer.setList(pageInfo.getList());
		} finally {
			PageMethod.clearPage();
		}

		return answer;
	}

	protected static Iterable<Object> criteriaIn(PageParamUser param, String key) {
		return criteriaIn(param.getParams(), key);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected static Iterable<Object> criteriaIn(Map<String, Object> param, String key) {
		Object val = (param == null ? null : param.get(key));

		Collection<Object> answer = null;
		if (ArrayUtil.isArray(val)) {
			answer = Arrays.asList((Object[]) val);
		} else if (val instanceof Collection) {
			answer = (Collection<Object>) val;
		} else if (val instanceof Map) {
			answer = ((Map) val).values();
		} else if (val != null) {
			answer = Arrays.asList(val);
		} else {
			return null;
		}

		// 如果返回值为空就返回null
		if (answer != null && !answer.isEmpty()) {
			return answer;
		} else {
			return null;
		}
	}

	protected static String criteriaLike(PageParamUser param, String key) {
		return criteriaLike(param.getParams(), key);
	}

	protected static String criteriaLike(Map<String, Object> param, String key) {
		Object val = param == null ? null : param.get(key);

		if (val != null && !"".equals(val)) {
			return "%" + val + "%";
		} else {
			return null;
		}
	}

	protected static Object criteriaEqual(PageParamUser param, String key) {
		return criteriaEqual(param.getParams(), key);
	}

	protected static Object criteriaEqual(Map<String, Object> param, String key) {
		return param == null ? null : param.get(key);
	}
}
